﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using Microsoft.Reputation.Tests.FrontEndCommon;

namespace Microsoft.Reputation.Services
{
    public partial class BlockOverrule
    {
        private BlockOverrule() { }
        public BlockOverrule(
            Action action,
            uint category,
            string hostString,
            string urlString)
        {
            this.ActionField = action;
            this.CategoryIdField = category;
            this.HostString = hostString;
            this.UrlStringField = urlString;
        }
        public override bool Equals(object obj)
        {
            if ((obj == null))
            {
                return true;
            }

            BlockOverrule data = obj as BlockOverrule;
            if (data == null)
            {
                return false;
            }

            return ((this.ActionField == data.ActionField) &&
                (this.CategoryIdField == data.CategoryIdField) &&
                // We are comparing the Strings for Null and Empty here rather than just doing a this.String == data.String, because
                // depending on whether we pass the string as Null or Empty, the data looks different in the Fiddler upload. But once the data gets to the server,
                // if its Null or Empty, a node for that String is NOT written in the log file. So when we de-serialize the log file, the string is always read in as Null.
                // So when we do this.String == data.String, and we are comparing a Null string with Empty string, the result will be FALSE.
                (String.IsNullOrEmpty(this.HostStringField) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.HostStringField)) ? true : this.HostStringField == Convertor.ConvertToBase64String(data.HostStringField)) &&
                (String.IsNullOrEmpty(this.UrlStringField) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.UrlStringField)) ? true : this.UrlStringField == Convertor.ConvertToBase64String(data.UrlStringField)));
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

    public partial class CategoryCount
    {
        private CategoryCount() { }
        public CategoryCount(
            uint categoryId,
            uint count)
        {
            this.CategoryId = categoryId;
            this.CountField = count;
        }
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            CategoryCount data = obj as CategoryCount;
            if (data == null)
            {
                return false;
            }

            return ((this.CategoryId == data.CategoryId) &&
                (this.CountField == data.CountField));
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

    public partial class OverrideException
    {
        private OverrideException() { }
        public OverrideException(
            uint[] categoryIdList,
            string hostString,
            string urlString)
        {
            this.CategoryIds = categoryIdList;
            this.HostString = hostString;
            this.UrlString = urlString;
        }
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            OverrideException data = obj as OverrideException;
            if (data == null)
            {
                return false;
            }

            bool retVal = ((this.CategoryIds.Length == data.CategoryIds.Length) &&
                           (String.IsNullOrEmpty(this.HostStringField) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.HostStringField)) ? true : this.HostStringField == Convertor.ConvertToBase64String(data.HostStringField)) &&
                           (String.IsNullOrEmpty(this.UrlStringField) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.UrlStringField)) ? true : this.UrlStringField == Convertor.ConvertToBase64String(data.UrlStringField)));
            if (!retVal) return retVal;

            for (int index = 0; index < CategoryIds.Length; index++)
            {
               retVal = retVal && (this.CategoryIds[index] == data.CategoryIds[index]);
            }
            return retVal;                
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

    public partial class SampleUrl
    {
        private SampleUrl() { }

        public SampleUrl(
            uint count,
            string hostString,
            uint sampleRate,
            string urlString)
        {
            this.CountField = count;
            this.HostString = hostString;
            this.SampleRateField = sampleRate;
            this.UrlStringField = urlString;
        }
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            // With the DCR 1461, all the strings in UrlTelemetry are now stored as Base64 strings.
            // The variable 'data' below, is the original Telemetry which was uploaded and the calling object is the data Serialized from the log file.
            // So we will convert the string member variables of 'data' in Base64 format.

            SampleUrl data = obj as SampleUrl;
            if (data == null)
            {
                return false;
            }

            return ((this.CountField == data.CountField) &&
                (String.IsNullOrEmpty(this.HostStringField) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.HostStringField)) ? true : this.HostStringField == Convertor.ConvertToBase64String(data.HostStringField)) &&
                (this.SampleRateField == data.SampleRateField) &&
                (String.IsNullOrEmpty(this.UrlStringField) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.UrlStringField)) ? true : this.UrlStringField == Convertor.ConvertToBase64String(data.UrlStringField)));
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

    public partial class UrlCounts
    {
        private UrlCounts() { }

        public UrlCounts(
            uint known,
            uint total,
            uint unknown)
        {
            this.KnownField = known;
            this.TotalField = total;
            this.UnknownField = unknown;
        }
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                Console.WriteLine("UrlCounts:Equals:: no data returned from the log file");
                return false;
            }

            UrlCounts data = obj as UrlCounts;
            if (data == null)
            {
                Console.WriteLine("UrlCounts:Equals:: data cannot be converted to UrlCounts type");
                return false;
            }

            return ((this.KnownField == data.KnownField) &&
                (this.TotalField == data.TotalField) &&
                (this.UnknownField == data.UnknownField));
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

    public partial class SuggestedCategory
    {
        public SuggestedCategory(
            uint value,
            uint catId)
        {
            this.Value = value;
            this.id = catId;
        }
        private SuggestedCategory()
        { 
        }
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            SuggestedCategory data = obj as SuggestedCategory;
            if (data == null)
            {
                return false;
            }
            //Code commented out but not removed as its useful for Debugging.
            //Console.WriteLine("Category value {0} == {1}", this.Value, data.Value);
            //Console.WriteLine("Category id {0} == {1}", this.id, data.id);

            return ((this.Value == data.Value) &&
                (this.id == data.id));
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
    public class UrlTelemetryLog
    {
        [XmlAttribute(AttributeName = "SchemaVersion")]
        public string SchemaVersion = "1.0";
        [XmlAttribute(AttributeName = "Time")]
        public DateTime timestamp = DateTime.UtcNow;
        [XmlAttribute(AttributeName = "Client")]
        public Guid ClientId;
        [XmlAttribute(AttributeName = "Customer")]
        public Guid CustomerId;
        [XmlAttribute(AttributeName = "Deployment")]
        public Guid DeploymentId;
        [XmlAttribute(AttributeName = "Version")]
        public string CustomerVersion;
        [XmlElement(ElementName = "Telemetry")]
        public UrlTelemetryTest URLTelemetry;

        private UrlTelemetryLog()
        {
        }
        public override bool Equals(System.Object obj)
        {
            if (obj == null)
            {
                Console.WriteLine("UrlTelemetryLog:Equals:: no data returned from the log file");
                return false;
            }

            UrlTelemetryLog data = obj as UrlTelemetryLog;
            if (data == null)
            {
                Console.WriteLine("UrlTelemetryLog:Equals:: data cannot be converted to UrlTelemetryLog type");
                return false;
            }

            return ((this.SchemaVersion == data.SchemaVersion) &&
                (this.timestamp == data.timestamp) &&
                (this.ClientId == data.ClientId) &&
                (this.CustomerId == data.CustomerId) &&
                (this.DeploymentId == data.DeploymentId) &&
                (this.CustomerVersion == data.CustomerVersion) &&
                (this.URLTelemetry.Equals(data.URLTelemetry))
                );
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

    public class UrlTelemetryTest
    {
        /* Only StartTime, EndTime & UrlCounts are required field 
         * That means while overloading Equals we've to make sure 
         * that null compariasion is a success 
         */

        [XmlElement(ElementName = "StartTime")]
        public DateTime StartTime;
        [XmlElement(ElementName = "EndTime")]
        public DateTime EndTime;
        [XmlElement(ElementName = "UrlCounts")]
        public UrlCounts UrlCounts;
        [XmlArray(ElementName = "SampleUrls")]
        public List<SampleUrl> SampleUrls;
        [XmlArray(ElementName = "CategoryPrecedenceCountList")]
        public List<CategoryCount> CategoryPrecedenceCountList;
        [XmlArray(ElementName = "CategoryCountList")]
        public List<CategoryCount> CategoryCountList;
        [XmlArray(ElementName = "OverrideExceptionList")]
        public List<OverrideException> OverrideExceptionList;
        [XmlArray(ElementName = "BlockOverruleList")]
        public List<BlockOverrule> BlockOverruleList;

        private UrlTelemetryTest()
        {
        }

        public override bool Equals(System.Object obj)
        {
            if (obj == null)
            {
                Console.WriteLine("UrlTelemetryTest:Equals:: no data returned from the log file");
                return false;
            }

            UrlTelemetry data = obj as UrlTelemetry;
            if (data == null)
            {
                Console.WriteLine("UrlTelemetryTest:Equals:: data cannot be converted to UrlTelemetry type");
                return false;
            }
            Console.WriteLine("Checking for object counts...");

            bool retVal = ((this.StartTime == data.StartTime) &&
                (this.EndTime == data.EndTime) &&
                ((this.UrlCounts == null && data.UrlCounts == null) ? true : this.UrlCounts.Equals(data.UrlCounts)) &&
                ((this.SampleUrls.Count == 0 && data.SampleUrls == null) ? true : this.SampleUrls.Count == data.SampleUrls.Length) &&
                ((this.CategoryPrecedenceCountList.Count == 0 && data.CategoryPrecedenceCountList == null) ? true : this.CategoryPrecedenceCountList.Count == data.CategoryPrecedenceCountList.Length) &&
                ((this.CategoryCountList.Count == 0 && data.CategoryCountList == null) ? true : this.CategoryCountList.Count == data.CategoryCountList.Length) &&
                ((this.OverrideExceptionList.Count == 0 && data.OverrideExceptionList == null) ? true : this.OverrideExceptionList.Count == data.OverrideExceptionList.Length) &&
                ((this.BlockOverruleList.Count == 0 && data.BlockOverruleList == null) ? true : this.BlockOverruleList.Count == data.BlockOverruleList.Length));

            if (!retVal) return retVal;
            Console.WriteLine("URLTelemetyTest:Equals:: counts/lengths matches for both objects");

            for (int index = 0; index < SampleUrls.Count; index++)
            {
                retVal = retVal && this.SampleUrls[index].Equals(data.SampleUrls[index]);
            }
            if (!retVal) return retVal;
            Console.WriteLine("URLTelemetyTest:Equals:: SampleURLs matches for both objects");

            for (int index = 0; index < CategoryPrecedenceCountList.Count; index++)
            {
                retVal = retVal && this.CategoryPrecedenceCountList[index].Equals(data.CategoryPrecedenceCountList[index]);
            }
            if (!retVal) return retVal;
            Console.WriteLine("URLTelemetyTest:Equals:: CategoryPrecedenceCountList matches for both objects");

            for (int index = 0; index < CategoryCountList.Count; index++)
            {
                retVal = retVal && this.CategoryCountList[index].Equals(data.CategoryCountList[index]);
            }
            if (!retVal) return retVal;
            Console.WriteLine("URLTelemetyTest:Equals:: CategoryCountList matches for both objects");

            for (int index = 0; index < OverrideExceptionList.Count; index++)
            {
                retVal = retVal && this.OverrideExceptionList[index].Equals(data.OverrideExceptionList[index]);
            }
            if (!retVal) return retVal;
            Console.WriteLine("URLTelemetyTest:Equals:: OverrideExceptionList matches for both objects");

            for (int index = 0; index < BlockOverruleList.Count; index++)
            {
                retVal = retVal && this.BlockOverruleList[index].Equals(data.BlockOverruleList[index]);
            }
            if(retVal)  Console.WriteLine("URLTelemetyTest:Equals:: BlockOverruleList matches for both objects");

            return retVal;
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
    public class UrlErrorReportLog
    {
        [XmlAttribute(AttributeName = "SchemaVersion")]
        public string SchemaVersion;
        [XmlAttribute(AttributeName = "Time")]
        public DateTime timestamp;
        [XmlAttribute(AttributeName = "Client")]
        public Guid ClientId;
        [XmlAttribute(AttributeName = "Customer")]
        public Guid CustomerId;
        [XmlAttribute(AttributeName = "Deployment")]
        public Guid DeploymentId;
        [XmlAttribute(AttributeName = "Version")]
        public string CustomerVersion;
        [XmlElement(ElementName = "ErrorReport")]
        public List<UrlErrorReportTest> UrlErrorReports;

        private UrlErrorReportLog()
        { 
        }
    }

    public partial class UrlErrorReportTest
    {
        [XmlElement(ElementName = "ReportCustomerID")]
        public Guid ReportCustomerID;
        [XmlElement(ElementName = "ReportDeploymentID")]
        public Guid ReportDeploymentID;
        [XmlElement(ElementName = "ReportClientID")]
        public Guid ReportClientID;
        [XmlElement(ElementName = "ReportCustomerVersion")]
        public string ReportCustomerVersion;
        [XmlElement(ElementName = "ReportLocale")]
        public string ReportLocale;
        [XmlElement(ElementName = "TargetURL")]
        public string TargetURL;
        [XmlElement(ElementName = "DisputedCategoryID")]
        public uint DisputedCategoryID;
        [XmlElement(ElementName = "ReportFidelity")]
        public uint ReportFidelity;
        [XmlElement(ElementName = "SiteOwnerEmail")]
        public string SiteOwnerEmail;
        [XmlElement(ElementName = "SiteOwnerPhone")]
        public string SiteOwnerPhone;
        [XmlElement(ElementName = "SiteOwnerName")]
        public string SiteOwnerName;
        [XmlElement(ElementName = "Comments")]
        public string Comments;
        [XmlElement(ElementName = "ClientIPAddress")]
        public string ClientIPAddress;
        [XmlElement(ElementName = "IsSiteOwner")]
        public bool IsSiteOwner;
        [XmlArray(ElementName = "SuggestedCategories")]
        public List<SuggestedCategory> SuggestedCategories;

        private UrlErrorReportTest()
        { 
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                Console.WriteLine("UrlErrorReportTest:Equals:: no data returned from the log file");
                return false;
            }

            UrlErrorReport data = obj as UrlErrorReport;
            if (data == null)
            {
                Console.WriteLine("UrlErrorReportTest:Equals:: data cannot be converted to UrlErrorReport type");
                return false;
            }

            //Code commented out but not removed as its useful for Debugging.
            //Console.WriteLine("ReportCustomerID {0} == {1}", this.ReportCustomerID, data.ReportCustomerID);
            //Console.WriteLine("ReportDeploymentID {0} == {1}", this.ReportDeploymentID, data.ReportDeploymentID);
            //Console.WriteLine("ReportClientID {0} == {1}", this.ReportClientID, data.ReportClientID);
            //Console.WriteLine("ReportLocale {0} == {1}", this.ReportLocale, data.ReportLocale);
            //Console.WriteLine("TargetURL {0} == {1}", this.TargetURL, data.TargetURL);
            //Console.WriteLine("DisputedCategoryID {0} == {1}", this.DisputedCategoryID, data.DisputedCategoryID);
            //Console.WriteLine("ReportFidelity {0} == {1}", this.ReportFidelity, data.ReportFidelity);
            //Console.WriteLine("SiteOwnerEmail {0} == {1}", this.SiteOwnerEmail, data.SiteOwnerEmail);
            //Console.WriteLine("SiteOwnerPhone {0} == {1}", this.SiteOwnerPhone, data.SiteOwnerPhone);
            //Console.WriteLine("SiteOwnerName {0} == {1}", this.SiteOwnerName, data.SiteOwnerName);
            //Console.WriteLine("Comments {0} == {1}", this.Comments, data.Comments);
            //Console.WriteLine("ClientIPAddress {0} == {1}", this.ClientIPAddress, data.ClientIPAddress);
            //Console.WriteLine("IsSiteOwner {0} == {1}", this.IsSiteOwner, data.IsSiteOwner);
            //Console.WriteLine("SuggestedCategories.Count {0} == {1}", this.SuggestedCategories.Count, data.SuggestedCategories.Length);
            
            bool retVal = ((this.ReportCustomerID == data.ReportCustomerID) &&
                (this.ReportDeploymentID == data.ReportDeploymentID) &&
                (this.ReportClientID == data.ReportClientID) &&
                (String.IsNullOrEmpty(this.ReportCustomerVersion) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.ReportCustomerVersion)) ? true : this.ReportCustomerVersion == Convertor.ConvertToBase64String(data.ReportCustomerVersion)) &&
                (String.IsNullOrEmpty(this.ReportLocale) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.ReportLocale)) ? true : this.ReportLocale == Convertor.ConvertToBase64String(data.ReportLocale)) &&
                (String.IsNullOrEmpty(this.TargetURL) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.TargetURL)) ? true : this.TargetURL == Convertor.ConvertToBase64String(data.TargetURL)) &&
                (this.DisputedCategoryID == data.DisputedCategoryID) &&
                (this.ReportFidelity == data.ReportFidelity) &&
                (String.IsNullOrEmpty(this.SiteOwnerEmail) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.SiteOwnerEmail)) ? true : this.SiteOwnerEmail == Convertor.ConvertToBase64String(data.SiteOwnerEmail)) &&
                (String.IsNullOrEmpty(this.SiteOwnerPhone) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.SiteOwnerPhone)) ? true : this.SiteOwnerPhone == Convertor.ConvertToBase64String(data.SiteOwnerPhone)) &&
                (String.IsNullOrEmpty(this.SiteOwnerName) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.SiteOwnerName)) ? true : this.SiteOwnerName == Convertor.ConvertToBase64String(data.SiteOwnerName)) &&
                (String.IsNullOrEmpty(this.Comments) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.Comments)) ? true : this.Comments == Convertor.ConvertToBase64String(data.Comments)) &&
                (String.IsNullOrEmpty(this.ClientIPAddress) && String.IsNullOrEmpty(Convertor.ConvertToBase64String(data.ClientIPAddress)) ? true : this.ClientIPAddress == Convertor.ConvertToBase64String(data.ClientIPAddress)) &&
                (this.IsSiteOwner == data.IsSiteOwner) &&
                (this.SuggestedCategories.Count == data.SuggestedCategories.Length)
                );
            if(retVal)
            {
                Console.WriteLine("Everything else matches now digging into categories...");
            }

            for (int index = 0; index < SuggestedCategories.Count; index++)
            {
                retVal = retVal && this.SuggestedCategories[index].Equals(data.SuggestedCategories[index]);
            }
            return retVal;
        }
    
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
}